{ "cells": [ { "cell_type": "markdown", "id": "d1d00572-29aa-4f27-a59c-f9f05889da7d", "metadata": {}, "source": [ "# Tutorial: Generating and handling ensemble data\n" ] }, { "cell_type": "markdown", "id": "e91e8928", "metadata": {}, "source": [ "## Introduction to population ensembles\n", "\n", "In *binary_c* one can add up stellar population data very easily. This is usually done in something called a population ensemble, which - if you are familiar to *Python* or *Perl* - is just an associative array, called a `dict` in *Python* or `hash` in *Perl*. The libcdict library performs such tasks in native C in *binary_c*, so is extremely fast and sufficiently flexible for our needs.\n", "\n", "The code to generate ensemble data is already set up in the `src/ensemble/` directory of *binary_c*. You can either use one of the pre-existing sets of ensemble-logging code, or write your own and put it in `src/ensemble/ensemble_log.c`, or attach it through the `extra_ensemble` *binary_c* function hook. \n", "\n", "To select the data that go into an ensemble, the `ensemble_log()` function applies a series of tests every timestep. \n", "\n", "Data are stored in the ensemble every so often: you can choose whether this output uses linear or logarithmic timesteps. You probably do not want the timestep to be too short because if is it your dataset will be overwhelmingly large.\n", "\n", "Please be careful when defining your own ensemble-logging functionality. You almost certainly want to bin your data appropriately using *binary_c*'s `Bin_data(value,binwidth)` macro. Please see `src/ensemble/ensemble_log.c` for many examples.\n", "\n", "You can find much more detailed explanations of ensembles in the *binary_c* documentation available at https://binary_c.gitlab.io/ in *The binary_c ensemble* section." ] }, { "cell_type": "markdown", "id": "c3730009-6d0e-4440-af55-a0236c1b39db", "metadata": { "tags": [] }, "source": [ "## How to generate ensemble data\n", "\n", "Ensemble data is generated from the properties of a population of stars, so first let's set up such a population.\n", "\n", "The resolution, ```r```, is the number of stars along each side of a three-dimensional M1 x M2 x orbital period parameter space. You should increase ```r``` to match your CPU power and patience. \n", "\n", "You can set ```binaries``` to ```False``` to run only single stars. \n", "\n", "Stars are sampled according to probabilities computed from the distributions of Moe and di Stefano (2017). We sample in equal steps of log(M1) using the ```M1samplerfunc``` variable. This is a string of code that is executed by the ```population.Moe_di_Stefano_2017()``` setup function." ] }, { "cell_type": "code", "execution_count": 1, "id": "8dd67c2f-81df-454d-8c02-8a244384fdad", "metadata": {}, "outputs": [], "source": [ "import os\n", "import json\n", "\n", "from binarycpython.utils.custom_logging_functions import temp_dir\n", "from binarycpython import Population\n", "\n", "TMP_DIR = temp_dir(\"notebooks\", \"notebook_ensembles\", clean_path=True)\n", "\n", "data_dir = os.path.join(TMP_DIR, 'data_dir')\n", "os.makedirs(data_dir, exist_ok=True)\n", "\n", "population = Population(tmp_dir=TMP_DIR, verbosity=2)" ] }, { "cell_type": "code", "execution_count": 2, "id": "21a31e5c", "metadata": { "scrolled": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "adding: max_evolution_time=15000 to BSE_options\n", "adding: combine_ensemble_with_thread_joining=True to population_options\n", "adding: save_ensemble_chunks=False to population_options\n", "adding: minimum_timestep=1e-06 to BSE_options\n", "adding: log_runtime_systems=0 to population_options\n", "adding: verbosity=1 to population_options\n", "Added sampling variable: {\n", " \"name\": \"multiplicity\",\n", " \"parameter_name\": \"multiplicity\",\n", " \"longname\": \"multiplicity\",\n", " \"valuerange\": [\n", " 1,\n", " 2\n", " ],\n", " \"samplerfunc\": \"self.const_int(1, 2, 2)\",\n", " \"precode\": \"self.population_options[\\\"multiplicity\\\"] = multiplicity; self.bse_options[\\\"multiplicity\\\"] = multiplicity; options={'JSON': None, 'q_high_extrapolation_method': 'flat', 'multiplicity_model': 'Poisson', 'IMF_distribution': 'kroupa2001', 'q_low_extrapolation_method': 'flat', 'load data': True, 'clean cache': False, 'apply settings': True, 'clean load flag': False, 'clean all': False, 'setup grid': True, 'multiplicity': 2, 'samplerfuncs': {'ecc': [None, None, None], 'logP': [None, None, None], 'M': ['self.const_linear(math.log(0.08), math.log(80.0), 4)', None, None, None]}, 'multiplicity_modulator': [1, 1, 0, 0], 'Mmin': 0.08, 'resolutions': {'M': [4, 4, 0, 0], 'logP': [4, 0, 0], 'ecc': [0, 0, 0]}, 'normalize_multiplicities': 'merge', 'ranges': {'ecc': [0.0, 0.99], 'q': [None, None], 'M': [0.08, 80.0], 'logP': [0.0, 8.0]}}\",\n", " \"postcode\": null,\n", " \"probdist\": 1,\n", " \"dphasevol\": -1,\n", " \"condition\": \"([1, 1, 0, 0][int(multiplicity)-1] > 0)\",\n", " \"gridtype\": \"discrete\",\n", " \"branchpoint\": 0,\n", " \"branchcode\": null,\n", " \"topcode\": null,\n", " \"bottomcode\": null,\n", " \"sampling_variable_number\": 0,\n", " \"dry_parallel\": false,\n", " \"dependency_variables\": null\n", "}\n", "Added sampling variable: {\n", " \"name\": \"lnM_1\",\n", " \"parameter_name\": \"M_1\",\n", " \"longname\": \"Primary mass\",\n", " \"valuerange\": [\n", " \"np.log(0.08)\",\n", " \"np.log(80.0)\"\n", " ],\n", " \"samplerfunc\": \"self.const_linear(math.log(0.08), math.log(80.0), 4)\",\n", " \"precode\": \"M_1 = np.exp(lnM_1); options[\\\"M_1\\\"]=M_1\",\n", " \"postcode\": null,\n", " \"probdist\": \"self.Moe_di_Stefano_2017_pdf({'JSON': None, 'q_high_extrapolation_method': 'flat', 'multiplicity_model': 'Poisson', 'IMF_distribution': 'kroupa2001', 'q_low_extrapolation_method': 'flat', 'load data': True, 'clean cache': False, 'apply settings': True, 'clean load flag': False, 'clean all': False, 'setup grid': True, 'multiplicity': 2, 'samplerfuncs': {'ecc': [None, None, None], 'logP': [None, None, None], 'M': ['self.const_linear(math.log(0.08), math.log(80.0), 4)', None, None, None]}, 'multiplicity_modulator': [1, 1, 0, 0], 'Mmin': 0.08, 'resolutions': {'M': [4, 4, 0, 0], 'logP': [4, 0, 0], 'ecc': [0, 0, 0]}, 'normalize_multiplicities': 'merge', 'ranges': {'ecc': [0.0, 0.99], 'q': [None, None], 'M': [0.08, 80.0], 'logP': [0.0, 8.0]}, 'multiplicity': multiplicity, 'M_1': M_1}, verbosity=self.population_options['verbosity'])['total_probdens'] if multiplicity == 1 else 1\",\n", " \"dphasevol\": \"dlnM_1\",\n", " \"condition\": null,\n", " \"gridtype\": \"centred\",\n", " \"branchpoint\": 1,\n", " \"branchcode\": \"multiplicity == 1\",\n", " \"topcode\": null,\n", " \"bottomcode\": null,\n", " \"sampling_variable_number\": 1,\n", " \"dry_parallel\": false,\n", " \"dependency_variables\": null\n", "}\n", "Added sampling variable: {\n", " \"name\": \"log10per\",\n", " \"parameter_name\": \"orbital_period\",\n", " \"longname\": \"log10(Orbital_Period)\",\n", " \"valuerange\": [\n", " 0.0,\n", " 8.0\n", " ],\n", " \"samplerfunc\": \"self.const_linear(0.0, 8.0, 4)\",\n", " \"precode\": \"orbital_period = 10.0**log10per\\nqmin=0.08/M_1\\nqmax=maximum_mass_ratio_for_RLOF(M_1, orbital_period)\\n\",\n", " \"postcode\": null,\n", " \"probdist\": 1.0,\n", " \"dphasevol\": \"(0.43429448190325176 * dlog10per)\",\n", " \"condition\": \"(self.population_options[\\\"multiplicity\\\"] >= 2)\",\n", " \"gridtype\": \"centred\",\n", " \"branchpoint\": 0,\n", " \"branchcode\": null,\n", " \"topcode\": null,\n", " \"bottomcode\": null,\n", " \"sampling_variable_number\": 2,\n", " \"dry_parallel\": false,\n", " \"dependency_variables\": null\n", "}\n", "Added sampling variable: {\n", " \"name\": \"q\",\n", " \"parameter_name\": \"M_2\",\n", " \"longname\": \"Mass ratio\",\n", " \"valuerange\": [\n", " null,\n", " null\n", " ],\n", " \"samplerfunc\": \"self.const_linear(0.08/M_1, qmax, 4)\",\n", " \"precode\": \"\\nM_2 = q * M_1\\nsep = calc_sep_from_period(M_1, M_2, orbital_period)\\n \",\n", " \"postcode\": null,\n", " \"probdist\": 1,\n", " \"dphasevol\": \"dq\",\n", " \"condition\": null,\n", " \"gridtype\": \"centred\",\n", " \"branchpoint\": 0,\n", " \"branchcode\": null,\n", " \"topcode\": null,\n", " \"bottomcode\": null,\n", " \"sampling_variable_number\": 3,\n", " \"dry_parallel\": false,\n", " \"dependency_variables\": null\n", "}\n" ] } ], "source": [ "mmin = population.minimum_stellar_mass()\n", "mmax = 80.0 # Msun\n", "binaries = True\n", "\n", "r = 4 # resolution\n", "resolution = {\n", " 'M_1': r, # resolution in M1\n", " 'q' : r, # resolution in M2\n", " 'per': r, # resolution in orbital period\n", " 'ecc' : 0 # resolution in eccentricity\n", "}\n", "\n", "############################################################\n", "# Set population options\n", "#\n", "population.set(\n", " # Grid configuration\n", " max_evolution_time=15000, # 15000 Myr\n", " combine_ensemble_with_thread_joining=True, # always combine results in final thread\n", " save_ensemble_chunks = False, # we don't want to save the data to files\n", " minimum_timestep=1e-6, # 1e-6 Myr == 1 yr\n", " log_runtime_systems=0, # do not log systems (can be slow)\n", " verbosity=1, # 1 = some verbosity\n", " run_zero_probability_system=0, # skip zero-probability systems\n", ")\n", "\n", "# set the M1 sampling function\n", "M1samplerfunc=\"self.const_linear(math.log({min}), math.log({max}), {res})\".format(\n", " min = mmin,\n", " max = mmax,\n", " res = resolution[\"M_1\"]\n", ")\n", "\n", "# set the resolutions to be used\n", "Moe_resolutions = {\n", " \"M\": [resolution['M_1'], resolution['q'], 0, 0], # NB 0 for M1 means automatic\n", " \"logP\": [resolution['per'], 0, 0],\n", " \"ecc\": [resolution['ecc'], 0, 0] # 0 means no eccentricity distribution\n", "}\n", "\n", "# set the options for the Moe and di Stefano (2017) function\n", "moe_options = {\n", " \"normalize_multiplicities\": \"merge\",\n", " \"multiplicity\": 2 if binaries else 1,\n", " \"multiplicity_modulator\": [1, 1 if binaries else 0, 0, 0],\n", " \"resolutions\": Moe_resolutions,\n", " 'Mmin':mmin,\n", " \"ranges\": {\n", " \"M\": [\n", " mmin,\n", " mmax\n", " ],\n", " 'logP': [ 0.0, 8.0 ] # 0 < log_10(P) < 8\n", " },\n", " 'samplerfuncs' : {\n", " 'M' : [\n", " M1samplerfunc,\n", " None,\n", " None,\n", " None\n", " ]\n", " }\n", " }\n", "\n", "population.Moe_di_Stefano_2017(\n", " options=moe_options\n", " )" ] }, { "cell_type": "markdown", "id": "d1007c43", "metadata": {}, "source": [ "## Set ensemble options\n", "\n", "Next we should set up the ensemble options." ] }, { "cell_type": "code", "execution_count": 3, "id": "cd2300ba", "metadata": {}, "outputs": [], "source": [ "# Ensemble options\n", "population.set(\n", " # Turn on the ensemble\n", " ensemble = True,\n", " \n", " # we want to defer output of the ensemble\n", " # until the final star is run\n", " ensemble_defer = True,\n", " \n", " # we want to use log10(time) bins\n", " \n", " \n", " # time resolution\n", " # we output to the ensemble in either linear or logarithmic time: you\n", " # can set ensemble_logtimes to False for linear, True for logarithmic\n", " ensemble_logtimes = True,\n", " \n", " # and then you need to choose the time resolution\n", " ensemble_dt = 1000.0, # linear time resolution (used if logtimes==False, i.e. not in this example)\n", " ensemble_logdt = 0.1, # log10(time) resolution in dex (used if logtimes==True, i.e. in this example)\n", " \n", " # because we use log10(time) we cannot start measuring time at time=0\n", " # but should start soon after, here at 0.1 Myr\n", " ensemble_startlogtime = 0.1, \n", " \n", " # next we select which ensembles should be output\n", " #\n", " # We do not want to output all of them, so first turn them all off\n", " ensemble_filters_off = 1, # turn off all filters except...\n", " \n", " # then turn on those ensembles that you require\n", " #\n", " # The output for each is defined in binary_c in the function\n", " # ensemble_log() found in src/ensemble/ensemble_log.c\n", " #\n", " # and you can find a full list of filters in\n", " # src/ensemble/ensemble.def\n", " # (they are not all included here)\n", " #\n", " ensemble_filter_CHEMICAL_YIELDS = False, # require chemical yields\n", " ensemble_filter_SCALARS = True, # required scalar number counts\n", " ensemble_filter_TEST = False, # include test data\n", " ensemble_filter_INITIAL_DISTRIBUTIONS = False, # initial distributions\n", "\n", ")" ] }, { "cell_type": "markdown", "id": "4bcaf56d", "metadata": {}, "source": [ "Next we evolve the population. Please wait for it to finish: this will take longer if you have set the resolution to be a larger number." ] }, { "cell_type": "code", "execution_count": 4, "id": "1a747ac6", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Warning: No parse function set. Make sure you intended to do this.\n", "Write grid code to /tmp/binary_c_python-david/notebooks/notebook_ensembles/binary_c_grid_3b8635f60a5a4056a5a94f6bf1c367d2.py [dry_run = True]\n", "Doing a dry run of the grid.\n", "Grid has handled 30 stars with a total probability of 0.981585\n", "\n", "**********************************\n", "* Dry run *\n", "* Total starcount is 30 *\n", "* Total probability is 0.981585 *\n", "**********************************\n", "\n", "setting up the system_queue_filler now\n", "Write grid code to /tmp/binary_c_python-david/notebooks/notebook_ensembles/binary_c_grid_3b8635f60a5a4056a5a94f6bf1c367d2.py [dry_run = False]\n", "Signalling processes to stop\n", "\n", "****************************************************\n", "* Process 0 finished: *\n", "* generator started at 2023-05-19T11:35:22.549022 *\n", "* generator finished at 2023-05-19T11:35:26.719666 *\n", "* total: 4.17s *\n", "* of which 4.06s with binary_c *\n", "* Ran 30 systems *\n", "* with a total probability of 0.981585 *\n", "* This thread had 0 failing systems *\n", "* with a total failed probability of 0 *\n", "* Skipped a total of 3 zero-probability systems *\n", "* *\n", "****************************************************\n", "\n", "\n", "**********************************************************\n", "* Population-3b8635f60a5a4056a5a94f6bf1c367d2 finished! *\n", "* The total probability is 0.981585. *\n", "* It took a total of 4.57s to run 30 systems on 1 cores *\n", "* = 4.57s of CPU time. *\n", "* Maximum memory use 173.703 MB *\n", "**********************************************************\n", "\n", "No failed systems were found in this run.\n" ] }, { "data": { "text/plain": [ "{'population_id': '3b8635f60a5a4056a5a94f6bf1c367d2',\n", " 'evolution_type': 'grid',\n", " 'failed_count': 0,\n", " 'failed_prob': 0,\n", " 'failed_systems_error_codes': [],\n", " 'errors_exceeded': False,\n", " 'errors_found': False,\n", " 'total_probability': 0.9815845963697204,\n", " 'total_count': 30,\n", " 'start_timestamp': 1684492522.5212972,\n", " 'end_timestamp': 1684492527.0914335,\n", " 'time_elapsed': 4.570136308670044,\n", " 'total_mass_run': 408.2548715232803,\n", " 'total_probability_weighted_mass_run': 0.7680948022521784,\n", " 'zero_prob_stars_skipped': 3}" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Evolve grid\n", "population.evolve()" ] }, { "cell_type": "markdown", "id": "337bc0e4-5be6-4c45-b351-ba9c9418dc43", "metadata": {}, "source": [ "## How to handle ensemble data\n", "\n", "Ensemble data is stored in a dict in the population object, at \n", "\n", "```\n", "ensemble = population.grid_ensemble_results['ensemble']\n", "```\n", "\n", "One can loop over keys in the dict directly, or, as shown below, convert to JSON and output in a format that is both human readable and computer processable. " ] }, { "cell_type": "code", "execution_count": 5, "id": "2f8ca6fe", "metadata": { "tags": [] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Printing abridged output: \n", "{\n", " \"scalars\": {\n", " \"BINARY_BLUE_STRAGGLER\": {\n", " \"-0.1\": 5100.0,\n", " \"-0.2\": 5100.0,\n", " \"-0.3\": 5100.0,\n", " \"-0.4\": 5100.0,\n", " \"-0.5\": 5100.0,\n", " \"-0.6\": 5100.0,\n", " \"-0.7\": 5100.0,\n", " \"-0.8\": 5100.0,\n", " \"-0.9\": 5100.0,\n", " \"0\": 5100.0,\n", " \"0.1\": 5100.0,\n", " \"0.2\": 5100.0,\n", " \"0.3\": 5100.0,\n", " \"0.4\": 5100.0,\n", " \"0.5\": 5100.0,\n", " \"0.6\": 5100.0,\n", " \"0.7\": 5100.0,\n", " \"0.8\": 5100.0,\n", " \"0.9\": 5100.0,\n", " \"1\": 4924.577876078783,\n", " \"1.1\": 4926.172884057682,\n", " \"1.2\": 5016.719954573364,\n", " \"1.3\": 5100.0,\n", " \"1.4\": 5100.0,\n", " \"1.5\": 5100.0,\n", " \"1.6\": 5100.0,\n", " \"1.7\": 5100.0,\n", " \"1.8\": 5100.0,\n", " \"1.9\": 5100.0,\n", " \"2\": 5100.0,\n", " \"2.1\": 5100.0,\n", " \"2.2\": 5100.0,\n", " \"2.3\": 5100.0,\n", " \"2.4\": 5100.0,\n", " \"2.5\": 5100.0,\n", " \"2.6\": 5100.0,\n", " \"2.7\": 5100.0,\n", " \"2.8\": 4954.0147194797655,\n", " \"2.9\": 5100.0,\n", " \"3\": 5100.0,\n", " \"3.1\": 5100.0,\n", " \"3.2\": 5100.0,\n", " \"3.3\": 5100.0,\n", " \"3.4\": 5100.0,\n", " \"3.5\": 5100.0,\n", " \"3.6\": 5100.0,\n", " \"3.7\": 5100.0,\n", " \"3.8\": 5100.0,\n", " \"3.9\": 5100.0,\n", " \"4\": 5100.0,\n", " \"4.1\": 5100.0,\n", " \"4.2\": 5100.0\n", " },\n", " \"BLUE_STRAGGLER\": {\n", " \"1\": 0.0019199736971710975,\n", " \"1.1\": 0.0019359479374287001,\n", " \"1.2\": 0.0006362375548468333\n", " },\n", " \"BSG\": {\n", " \"-0.1\": 0.005607909982917069,\n", " \"-0.2\": 0.005607909982917072,\n", " \"-0.3\": 0.005607909982917073,\n", " \"-0.4\": 0.005607909982917071,\n", " \"-0.5\": 0.005607909982917072,\n", " \"-0.6\": 0.005607909982917072,\n", " \"-0.7\": 0.005607909982917072,\n", " \"-0.8\": 0.005607909982917073,\n", " \"0\": 0.005607909982917073,\n", " \"0.1\": 0.005607909982917073,\n", " \"0.2\": 0.005607909982917073,\n", " \"0.3\": 0.0056079099829170745,\n", " \"0.4\": 0.0056079099829170745,\n", " \"0.5\": 0.0056079099829170745,\n", " \"0.6\": 0.005607909982917068,\n", " \"0.7\": 0.005607909982917066,\n", " \"0.8\": 0.0061711582707625395,\n", " \"0.9\": 0.0065034468983274545,\n", " \"1\": 0.0019678502946268005,\n", " \"1.1\": 0.0019359479374287001,\n", " \"1.2\": 0.0006399995173114125\n", " },\n", " \"BSG_LUM\": {\n", " \"-0.1\": 465.5191651818834,\n", " \"-0.2\": 460.392224832812,\n", " \"-0.3\": 456.29583301972133,\n", " \"-0.4\": 453.27348250770524,\n", " \"-0.5\": 450.9316215895541,\n", " \"-0.6\": 448.84251185892276,\n", " \"-0.7\": 447.2064146771188,\n", " \"-0.8\": 445.92144094877807,\n", " \"0\": 472.3649148942722,\n", " \"0.1\": 481.22334926909423,\n", " \"0.2\": 493.11815327706427,\n", " \"0.3\": 509.21177670859254,\n", " \"0.4\": 531.2262266075203,\n", " \"0.5\": 562.0440342082067,\n", " \"0.6\": 606.035936673939,\n", " \"0.7\": 670.6063814725621,\n", " \"0.8\": 815.6337342686954,\n", " \"0.9\": 947.4237842712193,\n", " \"1\": 359.23555902016886,\n", " \"1.1\": 414.81910251305214,\n", " \"1.2\": 123.39250913219956\n", " },\n", " \"CHeB\": {\n", " \"0.9\": 2.793935424837457e-05,\n", " \"1\": 0.0013954712827206621,\n", " \"1.2\": 0.0002922201248659066,\n", " \"1.3\": 7.638832761615915e-05,\n", " \"2.2\": 0.0005587423713012249,\n", " \"2.3\": 0.00016537042412094138,\n", " \"2.8\": 0.017182152365608324,\n", " \"2.9\": 0.08441693085167577,\n", " \"3\": 0.0053641789323110155,\n", " \"3.1\": 0.0011526407204140866,\n", " \"3.6\": 0.0009091782936834672,\n", " \"3.7\": 0.0005332024348221244\n", " },\n", " \"CHeB_LUM\": {\n", " \"0.9\": 4.904275360104634,\n", " \"1\": 282.57147576989627,\n", " \"1.2\": 54.713436143298615,\n", " \"1.3\": 4.264579923259343,\n", " \"2.2\": 0.4665408495224178,\n", " \"2.3\": 0.1815348358535978,\n", " \"2.8\": 1.9254600469031078,\n", " \"2.9\": 9.075661993123175,\n", " \"3\": 0.4430953434467815,\n", " \"3.1\": 0.08133881555683144,\n", " \"3.6\": 0.07117273008614428,\n", " \"3.7\": 0.05923231245679924\n", " },\n", " \"COMENV_DETACHED\": {\n", " \"1.2\": 0.0002530722287064908\n", " },\n", " \"COMENV_GB_MERGER\": {\n", " \"2.8\": 0.00012544608346379797\n", " },\n", " \"COMENV_HG_DETACHED\": {\n", " \"1.2\": 8.18710741450789e-10\n", " },\n", " \"COMENV_HG_MERGER\": {\n", " \"0.9\": 0.0008770919833338064\n", " },\n", " \"COMENV_MERGER\": {\n", " \"0.9\": 0.0008770919833338064,\n", " \"2.8\": 0.00012544608346379797\n", " },\n", " \"COWD\": {\n", " \"2.3\": 0.0008721169883882842,\n", " \"2.4\": 0.001085382741463638,\n", " \"2.5\": 0.0010853827414636379,\n", " \"2.6\": 0.0010853827414636379,\n", " \"2.7\": 0.0010853827414636379,\n", " \"2.8\": 0.0010853827414636379,\n", " \"2.9\": 0.012822671114861373,\n", " \"3\": 0.10087960710054318,\n", " \"3.1\": 0.10625692062895202,\n", " \"3.2\": 0.10748718320385917,\n", " \"3.3\": 0.10751810622239019,\n", " \"3.4\": 0.10751810622239011,\n", " \"3.5\": 0.10751810622239019,\n", " \"3.6\": 0.10751810622239255,\n", " \"3.7\": 0.11481008057357076,\n", " \"3.8\": 0.11739309502819884,\n", " \"3.9\": 0.11739309502819867,\n", " \"4\": 0.11739309502819842,\n", " \"4.1\": 0.11739309502819852,\n", " \"4.2\": 0.11739309502819908\n", " },\n", " \"COWD_LUM\": {\n", " \"2.3\": 1.778572584242028e-05,\n", " \"2.4\": 5.3756640859410884e-06,\n", " \"2.5\": 2.4216346987451443e-06,\n", " \"2.6\": 1.3150602881568674e-06,\n", " \"2.7\": 7.854908743566147e-07,\n", " \"2.8\": 4.96518362138202e-07,\n", " \"2.9\": 0.0009260738742458075,\n", " \"3\": 0.0001726658668669032,\n", " \"3.1\": 7.730821627291823e-05,\n", " \"3.2\": 2.081983661385333e-05,\n", " \"3.3\": 1.0645373457720407e-05,\n", " \"3.4\": 6.386100489734644e-06,\n", " \"3.5\": 4.05214265513937e-06,\n", " \"3.6\": 2.6680198277019643e-06,\n", " \"3.7\": 1.471450044787078e-05,\n", " \"3.8\": 1.7579410675990394e-06,\n", " \"3.9\": 1.0988367129444205e-06,\n", " \"4\": 7.399876975417793e-07,\n", " \"4.1\": 5.184110995272241e-07,\n", " \"4.2\": 3.657711355308934e-07\n", " },\n", " \"DAVIES_RSG\": {\n", " \"0.9\": 2.48073249154573e-05,\n", " \"1\": 0.0013806237504989608,\n", " \"1.2\": 0.00028985004324987647,\n", " \"1.3\": 8.145371575199544e-05,\n", "...\n" ] } ], "source": [ "# convert the ensemble results to pretty JSON output\n", "# and show this \n", "import json\n", "\n", "ensemble = population.grid_ensemble_results['ensemble']\n", "json_buffer = json.dumps(ensemble,\n", " sort_keys = True,\n", " indent = True,\n", " ensure_ascii = True);\n", "\n", "print(\"Printing abridged output: \")\n", "print('\\n'.join(json_buffer.splitlines()[:200]))\n", "print(\"...\")" ] }, { "cell_type": "markdown", "id": "79872ba2", "metadata": {}, "source": [ "One can write the `grid_ensemble_results` output directly to a file, e.g.,\n", "\n", "```\n", "population.write_ensemble(filename,\n", " sort_keys=True,\n", " indent=4)\n", "```\n", "\n", "If your file ends in ```.bz2``` or ```.gz``` it is automatically compressed using either the bzip2 or gzip algorithm, respectively." ] }, { "cell_type": "markdown", "id": "a3aa8736", "metadata": {}, "source": [ "## Scalars\n", "\n", "We wanted to access the \"scalars\" part of the ensemble. This is a set of scalar properties of the stellar population that are a function of, in our case, log10(time).\n", "\n", "The scalars are found in\n", "```ensemble['scalars']```\n", "which we can output." ] }, { "cell_type": "code", "execution_count": 6, "id": "1509b4fa", "metadata": { "tags": [] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Printing abridged output: \n", "{\n", " \"BINARY_BLUE_STRAGGLER\": {\n", " \"-0.1\": 5100.0,\n", " \"-0.2\": 5100.0,\n", " \"-0.3\": 5100.0,\n", " \"-0.4\": 5100.0,\n", " \"-0.5\": 5100.0,\n", " \"-0.6\": 5100.0,\n", " \"-0.7\": 5100.0,\n", " \"-0.8\": 5100.0,\n", " \"-0.9\": 5100.0,\n", " \"0\": 5100.0,\n", " \"0.1\": 5100.0,\n", " \"0.2\": 5100.0,\n", " \"0.3\": 5100.0,\n", " \"0.4\": 5100.0,\n", " \"0.5\": 5100.0,\n", " \"0.6\": 5100.0,\n", " \"0.7\": 5100.0,\n", " \"0.8\": 5100.0,\n", " \"0.9\": 5100.0,\n", " \"1\": 4924.577876078783,\n", " \"1.1\": 4926.172884057682,\n", " \"1.2\": 5016.719954573364,\n", " \"1.3\": 5100.0,\n", " \"1.4\": 5100.0,\n", " \"1.5\": 5100.0,\n", " \"1.6\": 5100.0,\n", " \"1.7\": 5100.0,\n", " \"1.8\": 5100.0,\n", " \"1.9\": 5100.0,\n", " \"2\": 5100.0,\n", " \"2.1\": 5100.0,\n", " \"2.2\": 5100.0,\n", " \"2.3\": 5100.0,\n", " \"2.4\": 5100.0,\n", " \"2.5\": 5100.0,\n", " \"2.6\": 5100.0,\n", " \"2.7\": 5100.0,\n", " \"2.8\": 4954.0147194797655,\n", " \"2.9\": 5100.0,\n", " \"3\": 5100.0,\n", " \"3.1\": 5100.0,\n", " \"3.2\": 5100.0,\n", " \"3.3\": 5100.0,\n", " \"3.4\": 5100.0,\n", " \"3.5\": 5100.0,\n", " \"3.6\": 5100.0,\n", " \"3.7\": 5100.0,\n", " \"3.8\": 5100.0,\n", " \"3.9\": 5100.0,\n", " \"4\": 5100.0,\n", " \"4.1\": 5100.0,\n", " \"4.2\": 5100.0\n", " },\n", " \"BLUE_STRAGGLER\": {\n", " \"1\": 0.0019199736971710975,\n", " \"1.1\": 0.0019359479374287001,\n", " \"1.2\": 0.0006362375548468333\n", " },\n", " \"BSG\": {\n", " \"-0.1\": 0.005607909982917069,\n", " \"-0.2\": 0.005607909982917072,\n", " \"-0.3\": 0.005607909982917073,\n", " \"-0.4\": 0.005607909982917071,\n", " \"-0.5\": 0.005607909982917072,\n", " \"-0.6\": 0.005607909982917072,\n", " \"-0.7\": 0.005607909982917072,\n", " \"-0.8\": 0.005607909982917073,\n", " \"0\": 0.005607909982917073,\n", " \"0.1\": 0.005607909982917073,\n", " \"0.2\": 0.005607909982917073,\n", " \"0.3\": 0.0056079099829170745,\n", " \"0.4\": 0.0056079099829170745,\n", " \"0.5\": 0.0056079099829170745,\n", " \"0.6\": 0.005607909982917068,\n", " \"0.7\": 0.005607909982917066,\n", " \"0.8\": 0.0061711582707625395,\n", " \"0.9\": 0.0065034468983274545,\n", " \"1\": 0.0019678502946268005,\n", " \"1.1\": 0.0019359479374287001,\n", " \"1.2\": 0.0006399995173114125\n", " },\n", " \"BSG_LUM\": {\n", " \"-0.1\": 465.5191651818834,\n", " \"-0.2\": 460.392224832812,\n", " \"-0.3\": 456.29583301972133,\n", " \"-0.4\": 453.27348250770524,\n", " \"-0.5\": 450.9316215895541,\n", " \"-0.6\": 448.84251185892276,\n", " \"-0.7\": 447.2064146771188,\n", " \"-0.8\": 445.92144094877807,\n", " \"0\": 472.3649148942722,\n", " \"0.1\": 481.22334926909423,\n", " \"0.2\": 493.11815327706427,\n", " \"0.3\": 509.21177670859254,\n", " \"0.4\": 531.2262266075203,\n", " \"0.5\": 562.0440342082067,\n", " \"0.6\": 606.035936673939,\n", " \"0.7\": 670.6063814725621,\n", " \"0.8\": 815.6337342686954,\n", " \"0.9\": 947.4237842712193,\n", " \"1\": 359.23555902016886,\n", " \"1.1\": 414.81910251305214,\n", " \"1.2\": 123.39250913219956\n", " },\n", " \"CHeB\": {\n", " \"0.9\": 2.793935424837457e-05,\n", " \"1\": 0.0013954712827206621,\n", " \"1.2\": 0.0002922201248659066,\n", " \"1.3\": 7.638832761615915e-05,\n", " \"2.2\": 0.0005587423713012249,\n", " \"2.3\": 0.00016537042412094138,\n", " \"2.8\": 0.017182152365608324,\n", " \"2.9\": 0.08441693085167577,\n", " \"3\": 0.0053641789323110155,\n", " \"3.1\": 0.0011526407204140866,\n", " \"3.6\": 0.0009091782936834672,\n", " \"3.7\": 0.0005332024348221244\n", " },\n", " \"CHeB_LUM\": {\n", " \"0.9\": 4.904275360104634,\n", " \"1\": 282.57147576989627,\n", " \"1.2\": 54.713436143298615,\n", " \"1.3\": 4.264579923259343,\n", " \"2.2\": 0.4665408495224178,\n", " \"2.3\": 0.1815348358535978,\n", " \"2.8\": 1.9254600469031078,\n", " \"2.9\": 9.075661993123175,\n", " \"3\": 0.4430953434467815,\n", " \"3.1\": 0.08133881555683144,\n", " \"3.6\": 0.07117273008614428,\n", " \"3.7\": 0.05923231245679924\n", " },\n", " \"COMENV_DETACHED\": {\n", " \"1.2\": 0.0002530722287064908\n", " },\n", " \"COMENV_GB_MERGER\": {\n", " \"2.8\": 0.00012544608346379797\n", " },\n", " \"COMENV_HG_DETACHED\": {\n", " \"1.2\": 8.18710741450789e-10\n", " },\n", " \"COMENV_HG_MERGER\": {\n", " \"0.9\": 0.0008770919833338064\n", " },\n", " \"COMENV_MERGER\": {\n", " \"0.9\": 0.0008770919833338064,\n", " \"2.8\": 0.00012544608346379797\n", " },\n", " \"COWD\": {\n", " \"2.3\": 0.0008721169883882842,\n", " \"2.4\": 0.001085382741463638,\n", " \"2.5\": 0.0010853827414636379,\n", " \"2.6\": 0.0010853827414636379,\n", " \"2.7\": 0.0010853827414636379,\n", " \"2.8\": 0.0010853827414636379,\n", " \"2.9\": 0.012822671114861373,\n", " \"3\": 0.10087960710054318,\n", " \"3.1\": 0.10625692062895202,\n", " \"3.2\": 0.10748718320385917,\n", " \"3.3\": 0.10751810622239019,\n", " \"3.4\": 0.10751810622239011,\n", " \"3.5\": 0.10751810622239019,\n", " \"3.6\": 0.10751810622239255,\n", " \"3.7\": 0.11481008057357076,\n", " \"3.8\": 0.11739309502819884,\n", " \"3.9\": 0.11739309502819867,\n", " \"4\": 0.11739309502819842,\n", " \"4.1\": 0.11739309502819852,\n", " \"4.2\": 0.11739309502819908\n", " },\n", " \"COWD_LUM\": {\n", " \"2.3\": 1.778572584242028e-05,\n", " \"2.4\": 5.3756640859410884e-06,\n", " \"2.5\": 2.4216346987451443e-06,\n", " \"2.6\": 1.3150602881568674e-06,\n", " \"2.7\": 7.854908743566147e-07,\n", " \"2.8\": 4.96518362138202e-07,\n", " \"2.9\": 0.0009260738742458075,\n", " \"3\": 0.0001726658668669032,\n", " \"3.1\": 7.730821627291823e-05,\n", " \"3.2\": 2.081983661385333e-05,\n", " \"3.3\": 1.0645373457720407e-05,\n", " \"3.4\": 6.386100489734644e-06,\n", " \"3.5\": 4.05214265513937e-06,\n", " \"3.6\": 2.6680198277019643e-06,\n", " \"3.7\": 1.471450044787078e-05,\n", " \"3.8\": 1.7579410675990394e-06,\n", " \"3.9\": 1.0988367129444205e-06,\n", " \"4\": 7.399876975417793e-07,\n", " \"4.1\": 5.184110995272241e-07,\n", " \"4.2\": 3.657711355308934e-07\n", " },\n", " \"DAVIES_RSG\": {\n", " \"0.9\": 2.48073249154573e-05,\n", " \"1\": 0.0013806237504989608,\n", " \"1.2\": 0.00028985004324987647,\n", " \"1.3\": 8.145371575199544e-05,\n", " \"2.2\": 7.528383881549066e-05,\n", "...\n" ] } ], "source": [ "json_buffer = json.dumps(ensemble['scalars'],\n", " sort_keys = True,\n", " indent = True,\n", " ensure_ascii = True)\n", "\n", "print(\"Printing abridged output: \")\n", "print('\\n'.join(json_buffer.splitlines()[:200]))\n", "print(\"...\")" ] }, { "cell_type": "markdown", "id": "51d91596", "metadata": {}, "source": [ "Let's now output the number of hydrogen-shell burning red giant stars as a function of time. \n", "\n", "Note that we have to be careful here: ensemble dictionary keys are always stored as strings so if we want to convert the log10(time) to time, we have to first convert the string to a float. " ] }, { "cell_type": "code", "execution_count": 7, "id": "3aea6c3d", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " 158.489 1.65257e-05\n", " 630.957 0.00418894\n", " 794.328 0.000298925\n", " 1000 6.96132e-05\n", " 1258.93 1.70586e-05\n", " 3981.07 0.00213166\n", " 5011.87 0.00089738\n" ] } ], "source": [ "stellar_type = 'GB'\n", "for time_string in ensemble['scalars']['GB']:\n", " time = float(time_string)\n", " print(f\"{10**time:20g} {ensemble['scalars']['GB'][time_string]:20g}\")" ] }, { "cell_type": "markdown", "id": "ed24edc0", "metadata": {}, "source": [ "## Mass in stars\n", "\n", "One can access the total mass formed into stars in the population using the following code. This is sometimes useful because if you want to generate data appropriate to galactic-chemical evolution you probably want these data to be per unit mass into stars formed. " ] }, { "cell_type": "code", "execution_count": 8, "id": "e4f8c124", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "mass in stars 0.7680948022521784\n" ] } ], "source": [ "mass_in_stars = population.grid_ensemble_results[\"metadata\"][\"total_probability_weighted_mass\"]\n", "print(f\"mass in stars {mass_in_stars}\")" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.9.9" } }, "nbformat": 4, "nbformat_minor": 5 }